/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package musicplayer;

/**
 *
 * @author Mr.D
 */
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
//import java.awt.Image;
//import java.awt.event.MouseAdapter;
//import java.awt.event.MouseEvent;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;
import java.awt.image.RescaleOp;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.sound.sampled.SourceDataLine;
import javax.swing.JPanel;
import kj.dsp.KJDigitalSignalProcessingAudioDataConsumer;
import kj.dsp.KJDigitalSignalProcessor;
import kj.dsp.KJFFT;

public class SpectrumAnalyzer extends JPanel implements KJDigitalSignalProcessor{
    private KJFFT fft;
    private float[] old_FFT;
    private int saFFTSampleSize;
    private int saBands;
    private float saMultiplier;
    private float saDecay = DEFAULT_SPECTRUM_ANALYSER_DECAY;
    private SourceDataLine m_line = null;
    public static final int DEFAULT_FPS = 50;
    public static final int DEFAULT_SPECTRUM_ANALYSER_FFT_SAMPLE_SIZE = 512;
    public static final int DEFAULT_SPECTRUM_ANALYSER_BAND_COUNT =20;
    public static final float DEFAULT_SPECTRUM_ANALYSER_DECAY = 0.05f;
    public static final int ModeOff = 0;
    public static final int ModeRealScope = 1;
    public static final int ModeSlowScope = 2;
    public static final int ModeBar = 3;
    public static final int ModeCircle = 4;
    public static final int ModeCircle2 = 5;
    public static final int ModeText = 6;
    public static final int ModeText2 = 7;
    public static final int ModeWater = 8;
    public static final int ModeSoul = 9;
    public static final int ModeColors = 10;
    public static final int ModeLight = 11;
    public static final int ModeHelp = 12;
    public static final int ModeAbout = 13;
    public static final int ModeInfo = 14;
    public static final int ModeHiddenHelp = 15;
    private boolean dspStarted = false;   
    private KJDigitalSignalProcessingAudioDataConsumer dsp = null;
    private int[] peaks = new int[DEFAULT_SPECTRUM_ANALYSER_BAND_COUNT];
    private int[] peaksDelay = new int[DEFAULT_SPECTRUM_ANALYSER_BAND_COUNT];
    private int height = 10;
    private int fps = DEFAULT_FPS;
    private int mode = ModeOff;

    private int[] x, y, barheight, barwidth, yp;
    private int xc1, yc1, xc2, yc2, xc3, yc3, xc4, yc4, xc5, yc5, wc1, hc1, wc2, hc2, wc3, hc3, wc4, hc4, wc5, hc5;
    //Cac bien dung de ve hinh
    private int scopedelay = 0;
    private int sx = 456, bar = 0;    
    private int xsd1, xsd2, xsd3, xsd4, xsd5, xsd6, xsd7, xsd8;
    private int sh1, sh2, sh3, sh4, sh5, sh6, sh7, sh8, sizes2;
    //Cac bien dung de ve kieu chu thu 2
    private int xs2, yt2;
    private int xmc1c2, ymc1c2, wmc1c2, hmc1c2, xmc2c2, ymc2c2, wmc2c2, hmc2c2, xmc3c2, ymc3c2, wmc3c2, hmc3c2, xmc4c2, ymc4c2, wmc4c2, hmc4c2, xmc5c2, ymc5c2, wmc5c2, hmc5c2, xmc6c2, ymc6c2, wmc6c2, hmc6c2;
    private int leftc2delay = 0, mc1heart = 55, rightc2delay = 0, mc2heart = 245, stringc2delay = 0, yss = 0;
    private int ysc2 = 160, oxc11 = 0, oxc12 = 0;
    private int xbc1c1, ybc1c1, wbc1c1, xbc2c1, ybc2c1, wbc2c1, xbc3c1, ybc3c1, wbc3c1, bc1c1delay = 2, bc2c1delay = 2,  bc3c1delay = 2;
    private Ellipse2D clipoval;
    private boolean wave = false, bc1c1ready = true, bc2c1ready = true, bc3c1ready = true;
    private int redcolor = 0, greencolor = 150;
    private boolean showtext = true, barnum = true;
    private double angle1 = 0, angle2 = Math.PI/4, angle3 = Math.PI/2, angle4 = Math.PI/2 + Math.PI/4, angle5 = Math.PI, angle6 = Math.PI + Math.PI/4, angle7 = 3*Math.PI/2, angle8 = 3*Math.PI/2 +Math.PI/4;
    private int d1 = 65;
    private int x1 = 0, y1 = 0, x2 = 0, y2 = 0, x3 = 0, y3 = 0, x4 = 0, y4 = 0, x5 = 0, y5 = 0, x6 = 0, y6 = 0, x7 = 0, y7 = 0, x8 = 0, y8 = 0;
    
    
    //Cac bien dung de ve Text2
    private TextLayout layout;
    private Font font;
    private FontRenderContext frc;
    private Graphics2D gd;
    //Cac bien dung de ve Image
    private Image avatar;
    private int imagex, imagew;
    //Cac bien dung de ve RealScope
    private int[] scope;
    private int blinkposition;
    private int controlselect, gainbarnum, volumelevel, panposition, panvalue, xname, xnamemax;
    private String songname = "";
    private int status;
    private boolean waiting = true;

    //Cac bien dung cho have soul
    private Image background;
    private float[] scales = { 1f, 1f, 1f, 1f };
    private float[] offsets = new float[4];
    private int xsword1, ysword1;
    private int xsword2, ysword2;
    private int xsword3, ysword3;
    private int xsword4, ysword4;
    private int xsword5, ysword5;
    private int xsword6, ysword6;
    private int xsword7, ysword7;
    private int xsword8, ysword8;
    private RescaleOp rop1, rop2, rop3, rop4;
    private BufferedImage bi, swordsoul1, swordsoul2;
    private Graphics soulg;
    private int sword4delay = 1;
    private boolean soulready = true;

    //Cac bien dung de ve colors
    private Random rd;
    private int[] shape, shapeheartx, shapehearty, xshape, shapered, shapegreen, shapeblue, arcstartangle, arcangle, arcwidth, archeight;

    //Cac bien dung de ve Bump
    //normal vector
    private float normalVectors[][];
    // image pixel array
    private int imgcolors[][];
    // double buffer
    int buffer[];
    private int Width, Height, lightx, lighty, lightdelay = 0;
    private float light = (float) 0.5;


    //Cac bien de ve rain
    int run = 0;
    int iwidth,iheight,hwidth,hheight;
    MemoryImageSource source;
    Image image;
    Graphics offGraphics;
    int ii,aa,bb;
//    int fps,delay;
    int size;
    short ripplemap[];
    int texture[];
    int ripple[];
    int oldind,newind,mapind;
    int riprad;
    Image im;
    BufferedImage offImage;

    //Cac bien dung cho file info
    String filepath = "", filename = "", title = "", artist = "", album = "", year = "", type = "", channel = "", bitrate = "", samplerate = "", layer = "";
    int filelength = 0;
    double filesize = 0;
    int durations = 0, durationm = 0, durationh = 0;
    boolean copyright = false, original = false;

    //Custom
    private String usertext = "Mr.D", userimagepath = "";

    public SpectrumAnalyzer() {
        setOpaque(false);
        initialize();        
    }
    public synchronized void process(float[] pLeft, float[] pRight, float pFrameRateRatioHint) {       
        if(this.getMode() == ModeBar)
            drawSpectrum(stereoMerge(pLeft, pRight), pFrameRateRatioHint);
        else if(this.getMode() == ModeCircle2){
            drawCircle2(stereoMerge(pLeft, pRight), pFrameRateRatioHint);
            drawCircle(pLeft, pRight, pFrameRateRatioHint, false);
            repaint();
        }
        else if(this.getMode() == ModeSlowScope)
            drawScope(stereoMerge(pLeft, pRight), pFrameRateRatioHint);
        else if(this.getMode() == ModeRealScope)
            setGraphicsRealScope(stereoMerge(pLeft, pRight));
        else if(this.getMode() == ModeCircle)
            drawCircle(pLeft, pRight, pFrameRateRatioHint, true);
        else if(this.getMode() == ModeText)
            drawText(stereoMerge(pLeft, pRight), pFrameRateRatioHint);
        else if(this.getMode() == ModeText2)
            drawText(stereoMerge(pLeft, pRight), pFrameRateRatioHint);
        else if(this.getMode() == ModeHelp)
            repaint();
        else if(this.getMode() == ModeAbout)
             drawText(stereoMerge(pLeft, pRight), pFrameRateRatioHint);    
        else if(this.getMode() == ModeOff)
            repaint();
        else if(this.getMode() == ModeWater)
            drawText(stereoMerge(pLeft, pRight), pFrameRateRatioHint);
        else if(this.getMode() == ModeSoul){
            drawSpectrum(stereoMerge(pLeft, pRight), pFrameRateRatioHint);
            drawSoul();
        }
        else if(this.getMode() == ModeColors){
            drawSpectrum(stereoMerge(pLeft, pRight), pFrameRateRatioHint);
        }
        else if(this.getMode() == ModeLight){
            drawText(stereoMerge(pLeft, pRight), pFrameRateRatioHint);
        }
        else if(this.getMode() == ModeInfo)
            repaint();
        else if(this.getMode() == ModeHiddenHelp)
            repaint();
    }
    @Override
    public void paintComponent(Graphics g) {
        if(this.getMode() == ModeCircle2){
            if((mc1heart+wmc1c2/2) > xc1)
                mc1heart = xc1 - wmc1c2/2 - 1;
            if( mc1heart < 55){
                if(leftc2delay  > 0){
                    leftc2delay  --;
                }
                else{
                    mc1heart++;
                    leftc2delay  = 1;
                }
            }            
            if((mc2heart-wmc4c2/2) < (xc1 + wc1))
                mc2heart = (xc1 + wc1) + wmc4c2/2 + 1;            
            if( mc2heart > 245){
                if(rightc2delay  > 0){
                    rightc2delay  --;
                }
                else{
                    mc2heart--;
                    rightc2delay  = 1;
                }
            }
            if((yc1 + wc1) > ysc2-10)
                ysc2 = (yc1 + wc1)+10;
            if( ysc2 > 160){
                if(stringc2delay  > 0){
                    stringc2delay  --;
                }
                else{
                    ysc2--;
                    stringc2delay  = 1;
                }
            }
            g.setColor(Color.LIGHT_GRAY);
            g.fillRect(0, 0, 310, 310);
            //Toa do tam O cua tat ca cac hinh tron la 110,80
            g.setColor(Color.BLACK);
            g.fillOval(xc1, yc1, wc1, hc1);
            g.setColor(Color.WHITE);
            g.fillOval(xc2, yc2, wc2, hc2);
            g.setColor(Color.BLACK);
            g.fillOval(xc3, yc3, wc3, hc3);
            g.setColor(Color.WHITE);
            g.fillOval(xc4, yc4, wc4, hc4);
            g.setColor(Color.BLACK);
            g.fillOval(xc5, yc5, wc5, hc5);
                      
            g.fillOval(xmc1c2, ymc1c2, wmc1c2, hmc1c2);    
            g.setColor(Color.WHITE);
            g.fillOval(xmc2c2, ymc2c2, wmc2c2, hmc2c2);
            g.setColor(Color.BLACK);
            g.fillOval(xmc3c2, ymc3c2, wmc3c2, hmc3c2);
            g.fillOval(xmc4c2, ymc4c2, wmc4c2, hmc4c2);
            g.setColor(Color.WHITE);
            g.fillOval(xmc5c2, ymc5c2, wmc5c2, hmc5c2);
            g.setColor(Color.BLACK);
            g.fillOval(xmc6c2, ymc6c2, wmc6c2, hmc6c2);
            if(sx == -180)
                sx = 300;
            if(showtext == true){
                g.drawString("Coi chừng chóng mặt ! (@_@)", sx, 15);
                g.drawString("Merge", 133, ysc2);
//                g.drawString("Left", xmc1c2+4, 160);
//                g.drawString("Right", xmc4c2+2, 160);
                g.drawString("Left", mc1heart-12, 160);
                g.drawString("Right", mc2heart-16, 160);
            }
            sx --;            
        }
        else if(this.getMode() == ModeBar){            
            g.setColor(Color.BLACK);
            g.fillRect(0, 0, 310, 310);
            for(bar = 0; bar < 20; bar++){
                redcolor = 0;
                greencolor = 150;
                if(barnum == false){
                    for(y[bar] = 165; y[bar] > (170-barheight[bar]); y[bar] -= 6){
                        greencolor +=20;
                        if(greencolor >= 255){
                            greencolor = 255;
                            redcolor +=30;
                        }
                        if(redcolor >= 255){
                            redcolor = 255;
                            greencolor -= 40;
                        }
                        if(greencolor <= 0){
                            greencolor = 0;
                        }
                        g.setColor(new Color(redcolor,greencolor,0));
                     }
                }
                for(y[bar] = 165; y[bar] > (170-barheight[bar]); y[bar] -= 6){
                    greencolor +=20;
                    if(greencolor >= 255){
                        greencolor = 255;
                        redcolor +=30;
                    }
                    if(redcolor >= 255){
                        redcolor = 255;
                        greencolor -= 40;
                    }
                    if(greencolor <= 0){
                        greencolor = 0;
                    }
                    if(barnum == true)
                        g.setColor(new Color(redcolor,greencolor,0));
                    if((y[bar] - (170-barheight[bar])) >= 5){
                            g.fillRect(x[bar], y[bar], barwidth[bar], 5);
                    }
                    else
                            g.fillRect(x[bar], (170-barheight[bar] )+5, barwidth[bar], y[bar]-(170-barheight[bar]));
                }
                yp[bar]+=5;
                if(yp[bar]>=168)
                    yp[bar] = 168;
            }
            g.setColor(Color.WHITE);
            for(bar = 0; bar < 20; bar++)
                g.fillRect(x[bar], yp[bar], 10, 2);
            if(showtext == true){
                if(barnum == true){
                    for(bar = 0; bar < 20; bar++)
                        g.drawString(Integer.toString(bar+1), x[bar], yp[bar] - 2);
                }
                else{   
                    for(bar = 0; bar < 20; bar++)
                        if(yp[bar] <= 15)
                            g.drawString("♫", x[bar], yp[bar] - 2);
                        else
                            g.drawString("♪", x[bar], yp[bar] - 2);
                }
            }
        }
        else if(this.getMode() == ModeCircle){
            g.setColor(Color.GRAY); 
            g.fillRect(0, 0, 310, 310);
            if(showtext == true){
                g.setColor(Color.CYAN);
                g.drawString("Coi chừng chóng mặt! (@_@)", sx, 105);
            }
            g.setColor(Color.GREEN);
            g.fillOval(xc1, yc1, wc1, hc1);
            g.setColor(Color.GRAY);
            g.setClip(clipoval);
            g.fillOval(xc5,yc5,wc5, hc5);
            if(showtext == true){
                g.setColor(Color.CYAN);
                g.drawString("Coi chừng chóng mặt! (@_@)", sx, 105);
            }
            g.setClip(null);
            
            g.setColor(Color.GREEN);
//            g.drawOval(xbc1c1, ybc1c1, wbc1c1, wbc1c1);
//            g.drawOval(xbc2c1, ybc2c1, wbc2c1, wbc2c1);
//            g.drawOval(xbc3c1, ybc3c1, wbc3c1, wbc3c1);
            if(sx == -180)
                sx = 300;
            if(showtext == true){
                g.drawString("Viền ngoài: Left", 5, 15);
                g.drawString("Viền trong: Right", 200, 15);
                }
            sx --;
//            g.drawLine(0, 100, 310, 100);
//            g.drawLine(150, 0, 150, 300);
            g.setColor(Color.BLUE);
            g.fillOval(x1 - 10, y1 - 10, 20, 20);
            g.fillOval(x2 - 10, y2 - 10, 20, 20);
            g.fillOval(x3 - 10, y3 - 10, 20, 20);
            g.fillOval(x4 - 10, y4 - 10, 20, 20);
            g.fillOval(x5 - 10, y5 - 10, 20, 20);
            g.fillOval(x6 - 10, y6 - 10, 20, 20);
            g.fillOval(x7 - 10, y7 - 10, 20, 20);
            g.fillOval(x8 - 10, y8 - 10, 20, 20);
        }
        else if(this.getMode() == ModeText){
//           g.clearRect(0, 0, 310, 310);
           g.setColor(Color.BLACK);
           g.drawString(usertext,xsd1,sh1);
           g.drawString(usertext,xsd2,sh2);
           g.drawString(usertext,xsd3,sh3);
           g.drawString(usertext,xsd4,sh4);
           g.drawString(usertext,xsd5,sh5);
           g.drawString(usertext,xsd6,sh6);
           g.drawString(usertext,xsd7,sh7);
           g.drawString(usertext,xsd8,sh8);
        }
        else if(this.getMode() == ModeText2){
             g.clearRect(0, 0, 310, 310);
             g.setColor(Color.BLACK);
             font = new Font("Times New Roman", Font.PLAIN, sizes2);
             gd = (Graphics2D)g;
             frc = gd.getFontRenderContext();
             layout = new TextLayout(usertext, font, frc);
             layout.draw(gd, xs2, yt2);
        }
        else if(this.getMode() == ModeSlowScope){
            g.setColor(Color.BLACK);
            g.fillRect(0, 0, 310, 310);
            g.setColor(Color.WHITE);                        
            for(bar = 0; bar <199; bar++)
                g.drawLine(250-bar, scope[bar], 249-bar, scope[bar+1]);
        }
        else if(this.getMode() == ModeHelp){
            g.clearRect(0, 0, 310, 310);
            g.setColor(Color.WHITE);
            g.fillRect(0, 0, 310, 310);
            g.setColor(Color.BLACK);
            g.drawString("Guide", 130, 15);
            g.drawString("File: Add a local audio File or Folder or Exit", 10, 40);
            g.drawString("Control: Control playback of audio file", 10, 60);
            g.drawString("View: Show Visualization, Option, File Info or Playlist", 10, 80);
            g.drawString("Help: Show Guide and Program Information", 10, 100);
            g.drawString("Support file type: mp1, mp2, mp3, ogg, wav, ...", 10, 120);
            g.drawString("You can drag and drop to add song", 8, 140);
            g.drawString("   This program is free software; you can redistribute", 8, 160);
            g.drawString("it and/or modify it under the terms of the GNU LGPL", 8, 180);
        }
        else if(this.getMode() == ModeAbout){
            g.clearRect(0, 0, 310, 310);
            g.setColor(Color.WHITE);
            g.fillRect(0, 0, 310, 310);
            g.setColor(Color.BLACK);
            g.drawString("Program Infomation", 100, 15);
            g.drawString("Name: JMusicPlayer", 10, 40);
            g.drawString("Release Version: 1.0.0(Beta)", 10, 60);
            g.drawString("Programing Language: JavaSE", 10, 80);
            //gd.drawImage(avatar, 60, 30, this);
            g.drawString("Programer: Ngô Thành Danh(Mr.D.MGD.D)", 10, 100);
            g.drawString("Working Time: < 150 hours", 10, 120);
            g.drawString("Contact: mrdmgdd@gmail.com", 10, 140);
            g.drawString("or mrdmgdd@yahoo.com", 45, 160);
            g.drawString("Special thanks to: javazoom", 10, 180);
            g.drawImage(avatar, imagex, imagex -80, imagew, imagew, this);           
        }
        else if(this.getMode() == ModeInfo){
            g.clearRect(0, 0, 310, 310);
            g.setColor(Color.WHITE);
            g.fillRect(0, 0, 310, 310);
            g.setColor(Color.BLACK);
//            g.drawLine(68, 0, 68, 300);
            g.drawString("File Informations", 100, 15);
            if(filepath.length()*7 + 60 > 300){
                if(filepath.length() - 38 >= 0){
                    filepath = filepath.substring(filepath.length() - 38, filepath.length());
                    g.drawString("Directory: .."+ filepath, 5, 40);
                }
                else{
                    filepath = filepath.substring(0, filepath.length());
                    g.drawString("Directory: "+ filepath, 5, 40);
                }
            }
            else
                g.drawString("Directory: "+ filepath, 5, 40);
            if(filename.length()*7 + 68 > 300){
                if(filename.length() - 36 >= 0){
                    filename = filename.substring(filename.length() - 36, filename.length());
                    g.drawString("File Name: .."+ filename, 5, 60);
                }
                else{
                    filename = filename.substring(0, filename.length());
                    g.drawString("File Name: "+ filename, 5, 60);
                }
            }
            else
            g.drawString("File Name: "+ filename, 5, 60);
            g.drawString("Size: "+ (int)filesize + " bytes", 5, 80);
            g.drawString("Type: "+type + " "+layer, 5, 100);
            g.drawString("Channel: "+ channel, 5, 120);            
            g.drawString("Bit rate: "+bitrate +" kbps", 5, 140);
            g.drawString("Sample rate: "+samplerate+" Hz", 5, 160);
            g.drawString("Duration: "+durationh+":"+durationm+":"+durations, 5, 180);
            g.drawString("Title: "+title, 155, 80);
            g.drawString("Artist: "+artist, 155, 100);
            g.drawString("Album: "+ album, 155, 120);
            g.drawString("Year: "+year, 155, 140);
            g.drawString("Original: "+original, 155, 160);
            g.drawString("Copyright: "+copyright, 155, 180);
        }
        else if(this.getMode() == ModeHiddenHelp){
            g.clearRect(0, 0, 310, 310);
            g.setColor(Color.BLACK);
            g.drawString("Hidden Help", 50, 15);
            g.drawString("hiddenhelp: Show this Hidden Help", 5, 40);
            g.drawString("showsysinfo: Show Java System Informations", 5, 60);
            g.drawString("showoption: Show last save Options", 5, 80);
            g.drawString("showsonglist: Show current Playlist's song", 5, 100);
            g.drawString("showdirlist: Show current Playlist's song url", 5, 120);
            g.drawString("showpathlist: Show current Playlist's song path", 5, 140);
        }
        else if(this.getMode() == ModeRealScope){             
            g.setColor(Color.BLACK);
            g.fillRect(0, 0, 310, 310);
            g.setColor(Color.WHITE);
            for(bar = 0; bar < 199; bar++)
                g.drawLine(250-bar, scope[bar], 249-bar, scope[bar+1]);
            //g.drawLine(ca, wLas, ca + 1, wAs);  
        }
        else if(this.getMode() == ModeOff){
            g.setColor(Color.BLACK);
            g.fillRect(0, 0, 310, 310);
            g.setColor(Color.WHITE);
            if(waiting)
                g.drawString("Click và kéo để di chuyển !", 70, 15);
            g.drawString("2 cái này vẽ, không phải hình", 75, 45);
            g.drawString("Trail version nên còn tiếng Việt !", 65, 60);
            g.setXORMode(Color.black);
            g.setColor(Color.red);
            g.fillRect(25, 75, 50, 50);
            g.setColor(Color.green);
            g.fillRect(50, 100, 50, 50);
            g.setColor(Color.red);
            g.fillOval(180, 80, 60, 60);
            g.setColor(Color.green);
            g.fillOval(170, 110, 70, 70);
            g.setColor(Color.blue);
            g.fillOval(210, 100, 50, 50);
            g.setPaintMode();

        }
        else if(this.getMode() == ModeWater){
            g.clearRect(0, 0, 310, 310); 
            repaint();
            newframe();
            source.newPixels();
            offGraphics.drawImage(image,0,0,iwidth,iheight,null);
            g.drawImage(offImage,0,0,this);
            if(sx == -160)
                sx = 300;
            if(showtext == true){
                g.setColor(Color.WHITE);
                g.drawString("Mưa.... Thực ra là Ripple Map", sx, 15);
            }
            sx --;
        }
        else if(this.getMode() == ModeSoul){            
            gd = (Graphics2D)g;
            gd.clearRect(0, 0, 300, 300);
            g.setColor(Color.BLACK);
            g.fillRect(0, 0, 310, 310);
            gd.drawImage(background, 50, 0, 200, 200, this);
            bi = null;
            bi = new BufferedImage(300, 300, BufferedImage.TYPE_INT_ARGB);
            soulg = bi.getGraphics();
            //May dong duoi la dung de ve phan tren kiem
            soulg.drawImage(swordsoul1, xsword1/2+2,  ysword1/2, (177 - xsword1)*2, (86 - ysword1)*2, null);
            gd.drawImage(bi, rop1, xsword1/2, ysword1/2);
            soulg.drawImage(swordsoul1, xsword2/2+2,  ysword2/2, (177 - xsword2)*2, (86 - ysword2)*2, null);
            gd.drawImage(bi, rop2, xsword2/2, ysword2/2);
            soulg.drawImage(swordsoul1, xsword3/2+2,  ysword3/2, (177 - xsword3)*2, (86 - ysword3)*2, null);
            gd.drawImage(bi, rop3, xsword3/2, ysword3/2);
            soulg.drawImage(swordsoul1, xsword4/2+2,  ysword4/2, (177 - xsword4)*2, (86 - ysword4)*2, null);
            gd.drawImage(bi, rop4, xsword4/2, ysword4/2);
            bi = null;
            bi = new BufferedImage(300, 300, BufferedImage.TYPE_INT_ARGB);
            soulg = bi.getGraphics();
//            //May dong duoi la dung de ve phan duoi kiem
            soulg.drawImage(swordsoul2, 185/2-1,  110/2, xsword5, ysword5, null);
            gd.drawImage(bi, rop1, 185/2-1, 110/2);
            soulg.drawImage(swordsoul2, 185/2-1,  110/2, xsword6, ysword6, null);
            gd.drawImage(bi, rop2, 185/2-1, 110/2);
            soulg.drawImage(swordsoul2, 185/2-1,  110/2, xsword7, ysword7, null);
            gd.drawImage(bi, rop3, 185/2-1, 110/2);
            soulg.drawImage(swordsoul2, 185/2-1,  110/2, xsword8, ysword8, null);
            gd.drawImage(bi, rop4, 185/2-1, 110/2);
            if(sx == -450)
                sx = 300;
            if(showtext == true){
                g.setColor(Color.WHITE);
                g.drawString("Một ví dụ về thay đổi độ trong suốt của hình ảnh, vẽ nhiều hình nên hơi nặng !", sx, 15);
            }
            sx --;
        }
        else if(this.getMode() == ModeColors){            
            g.setColor(Color.BLACK);
            g.fillRect(0,0,300,300);            
            g.setXORMode(Color.BLACK);
            for(int i = 0; i < 10; i++){
                if(shape[i] == 0){
                    g.setColor(new Color(shapered[i], shapegreen[i], shapeblue[i]));
                    g.fillRect(shapeheartx[i] - xshape[i], shapehearty[i] - xshape[i], xshape[i]*2, xshape[i]*2);
                }
                else if(shape[i] == 1){
                    g.setColor(new Color(shapered[i], shapegreen[i], shapeblue[i]));
                    g.fillOval(shapeheartx[i] - xshape[i], shapehearty[i] - xshape[i], xshape[i]*2, xshape[i]*2);
                }
                else if(shape[i] == 2){
                    g.setColor(new Color(shapered[i], shapegreen[i], shapeblue[i]));
                    g.fillArc(shapeheartx[i] - xshape[i], shapehearty[i] - xshape[i], xshape[i]*2, xshape[i]*2, arcstartangle[i], arcangle[i]);
                }
                else if(shape[i] == 3){
                    g.setColor(new Color(shapered[i], shapegreen[i], shapeblue[i]));
                    g.fillRoundRect(shapeheartx[i] - xshape[i], shapehearty[i] - xshape[i], xshape[i]*2, xshape[i]*2, arcwidth[i], archeight[i]);
                }
            }
            if(sx == -520)
                sx = 300;
            if(showtext == true){
                g.drawString("Cái này tuyệt nhất khi nghe những bài có nhiều Bass Drum và Hand Clap (ví dụ Nhạc vũ trường)", sx, 105);
            }
            sx --;
            g.setPaintMode();
        }
        else if(this.getMode() == ModeLight){
            lightdelay ++;
            light -= 0.01;
            if(light < 0)
                light = 0;
            int i, j;
            float intensity;

            int newR, newG, newB;
            int oldR, oldG, oldB;

            for (i = 0; i < Width; i++)
            {
                    for (j = 0; j < Height; j++)
                    {                        
                            intensity = BumpIntensity (lightx, lighty, i, j);
                        

                            // brighten slightly (ambient)
                            //Chinh do sang
//				intensity += 0.18;
                            
//                                intensity += 0.01;
                            intensity += light;
                                if (intensity > 1.0)
                                        intensity = (float)1.0;                                
                            oldR = imgcolors[j * Width + i][0];
                            oldG = imgcolors[j * Width + i][1];
                            oldB = imgcolors[j * Width + i][2];

                            newR = (int)(intensity * oldR);
                            newG = (int)(intensity * oldG);
                            newB = (int)(intensity * oldB);

//                             Color c = new Color (newR, newG, newB);
//                             g.setColor (c);
//                             g.drawLine (x, y, x, y);

                            buffer[j * Width + i] = (255 << 24) | (newR << 16) | (newG << 8) | newB;
                    }
            }

            Image blitthis = createImage (new MemoryImageSource (Width, Height, buffer, 0, Width));
            if(light > 0)
                g.drawImage (blitthis, 0, 0, this);
            else{
                g.setColor(Color.BLACK);
                g.fillRect(0, 0, 300, 300);
            }
            blitthis.flush ();
            if(sx == -140)
                sx = 300;
            if(showtext == true){
                g.setColor(Color.WHITE);
                g.drawString("Đây là Bump Mapping", sx, 15);
            }
            sx --;
        }
        g.setPaintMode();
        //Mau duoc chon ung voi nut mau den, chu xanh
        g.setColor(new Color(0,70,90));
        //Cac theme phai co: Default, RED, GREEN, BLUE, BLACK, WHITE, CYAN, PINK, GRAY va cac mau phu cua chung
//        g.setColor(Color.PINK);
        //Dong duoi de ve vung volume va balance va vung process
        g.fillRect(0, getHeight()-55, 305, 30);
//        g.setColor(Color.MAGENTA);
//        g.fillRect(0, getHeight()-55, 305, 55);
//        g.setXORMode(Color.GREEN);
        /* Danh sach cac theme, mau nut cung la mau nen
         * XORMode mau BLACK thi mau nen co cac gia tri dep:
         *  1. DARK_GRAY, nen dat ten la GRAY//
         *  2. GRAY, nen dat ten la DARK_GRAY
         *  3. PINK, nen dat ten la DARK_CYAN
         * XORMode mau BLUE thi mau nen co cac gia tri dep:
         *  1. DARK_GRAY, nen dat ten la DARK_YELLOW
         *  2. GRAY, nen dat ten la DARK_BLUE
         *  3. RED, nen dat ten la GREEN
         * XORMode mau CYAN thi mau nen co cac gia tri dep:
         *  1. BACK, nen dat ten la RED
         *  2. DARK_GRAY, nen dat ten la DARK_RED
         *  3. GRAY, nen dat ten la DARK_CYAN
         *  4. GREEN, nen dat ten la YELLOW and PINK// PINK la mau tren nut nhan
         *  5. MAGENTA, nen dat la BLUE and CYAN
         *  6. ORANGE, nen dat la LIGHT_GREEN and BLUE
         *  7. PINK, nen dat la LIGHT_CYAN and BLACK
         *  8. WHITE, nen dat ten la CYAN
         * XORMode mau DARK_GRAY thi mau nen co cac gia tri dep:
         *  1. LIGHT_GRAY, nen dat ten la DARK_GRAY//LAY
         * XORMode mau GRAY thi mau nen co cac gia tri dep:
         *  1. BLACK co the dat ten la DARK_GRAY
         * XORMode mau GREEN thi mau nen co cac gia tri dep:
         *  1.LIGHT_GRAY nen dat ten la GRAY_GREEN
         *  2.MAGENTA nen dat ten la PINK_BLACK
         *  3.PINK nen dat ten la HONG_GREEN
         *
         * */
         
        








          
        //Ve Volume bar
        g.setColor(Color.WHITE);
        for(bar = 0; bar < gainbarnum; bar++)
            g.fillRect((bar*6)+10, getHeight()-bar-40, 5, bar+2);
        //Ve Balance bar
        g.fillRect(230, getHeight()-47, 50, 4);
        //Ve control balance
        //Center la 255
        //Cuc phai la 228, cuc trai la 278
        //g.fillRect(224, getHeight()-50, 4, 10);
        g.fillRect(278-(50-panposition), getHeight()-50, 4, 10);
        g.drawLine(0,getHeight()-30, 305, getHeight()-30);
        if(status == 3)
            blinkposition =0;
        g.fillRect(blinkposition - 3, getHeight()-33, 6, 6);
        if(controlselect == 1)
            g.drawString("Volume: " + Integer.toString(volumelevel), 120, getHeight()-40);
        else if(controlselect == 2){
            if(panvalue == 0)
                g.drawString("Balance: Center", 100, getHeight()-40);
            else if(panvalue < 0)
                g.drawString("Balance: " + Integer.toString(panvalue*(-1))+ "% Left", 100, getHeight()-40);
            else if(panvalue > 0)
                g.drawString("Balance: " + Integer.toString(panvalue)+ "% Right", 100, getHeight()-40);
        }
        else
            g.drawString("", 130, getHeight() - 40);
        g.setColor(new Color(20, 200, 20));
        xname--;
        if(xname <= xnamemax)
            xname = 300;
        if(status == 1){
            g.drawString(songname, xname, getHeight() - 60);
            if(controlselect ==0){
                g.setColor(Color.WHITE);
                g.drawString("Playing", 130, getHeight()-40);
            }
        }
        else if(status == 2){
            g.setColor(new Color(20, 200, 20));
            g.drawString(songname, 0, getHeight() - 60);
            g.setColor(Color.WHITE);
            g.drawString("Paused", 130, getHeight()-40);
        }
        else if(status == 3){
            g.setColor(new Color(20, 200, 20));
            g.drawString(songname, 0, getHeight() - 60);
            g.setColor(Color.WHITE);
            g.drawString("Stoped", 130, getHeight()-40);
        }
//        g.setPaintMode();
        g.setColor(Color.MAGENTA);
        g.fillRect(0, getHeight()-25, 305, 25);
         //g.setColor(Color.blue);
         //g.setColor(Color.red);
        g.setXORMode(Color.GREEN);
    }
    public void setUserInfo(String text, String imagepath){
        if(!text.isEmpty())
            usertext = text;    
        if(!imagepath.isEmpty())
            userimagepath = imagepath;
        //Khoi tao cac bien bump
        Image lightbackground = this.getToolkit().getImage(userimagepath);
        Image map = this.getToolkit().getImage(userimagepath);
        MediaTracker imageTracker = new MediaTracker (this);
        imageTracker.addImage (lightbackground, 0);
        imageTracker.addImage (map, 0);
        try {
                imageTracker.waitForAll ();
        }
        catch (InterruptedException e) {
                System.err.println("interrupted waiting for images!");
        }
        Width = lightbackground.getWidth (this);
        Height = lightbackground.getHeight (this);
        normalVectors = new float[Width * Height][3];
        FindNormalVectors (map, normalVectors);
        imgcolors = new int[Width * Height][3];
        ImageToRGBArray (lightbackground, imgcolors);
        buffer = new int[Width * Height];
        lightbackground.flush ();
	map.flush ();
        lightx = rd.nextInt(300);
        lighty = rd.nextInt(200);
        //Khoi tao cac  bien rain
        MediaTracker mt = new MediaTracker(this);
        im = getToolkit().getImage(userimagepath);
        mt.addImage(im,0);
        try {
            mt.waitForID(0);
        } catch (InterruptedException e) {
            return;
        }
        iwidth = im.getWidth(this);
        iheight = im.getHeight(this);
        hwidth = iwidth>>1;
        hheight = iheight>>1;
        riprad=3;

        size = iwidth * (iheight+2) * 2;
        ripplemap = new short[size];
        ripple = new int[iwidth*iheight];
        texture = new int[iwidth*iheight];
        oldind = iwidth;
        newind = iwidth * (iheight+3);
        PixelGrabber pg = new PixelGrabber(im,0,0,iwidth,iheight,texture,0,iwidth);
          try {
                pg.grabPixels();
          } catch (InterruptedException e) {}
        source = new MemoryImageSource(iwidth, iheight, ripple, 0, iwidth);
        source.setAnimated(true);
        source.setFullBufferUpdates(true);
        image = createImage(source);
        offImage = new BufferedImage(iwidth, iheight, BufferedImage.TYPE_INT_ARGB);
        offGraphics = offImage.getGraphics();
    }
    public void setFileInfo(String path, String name, double size, String type, String layer, String samplerate, String bitrate, String channel, long duration, String title, String artist, String album, String year, boolean original, boolean copyright){        
        filepath = path;
        filename = name;
        filesize = size;
        this.type = type;
        this.layer = layer;
        this.samplerate = samplerate;
        this.bitrate = bitrate;
        this.channel = channel;
        durationm = (int)duration/60;
        durationh = durationm/60;
        durations = (int)duration - durationm*60 - durationh*3600;
        this.title = title;
        this.artist = artist;
        this.album = album;
        this.original = original;
        this.copyright = copyright;
        this.year = year;
    }
    private void FindNormalVectors (Image imagemap, float nv[][])
    {
            PixelGrabber pg;
//		int[] pixelarray;

            int imageWidth = imagemap.getWidth (this);
            int imageHeight = imagemap.getHeight (this);

            // get pixels into pixelarray
            int[] pixelarraymap = new int [imageWidth * imageHeight];

            pg = new PixelGrabber (imagemap, 0, 0, imageWidth, imageHeight, pixelarraymap, 0, imageWidth);

            try {
                    pg.grabPixels ();
            }
            catch (InterruptedException e) {
                    System.err.println("interrupted waiting for pixels!");
            }

            for (int xx = 1; xx < Width - 1; xx++)
            {
                    for (int yy = 1; yy < Height - 1; yy++)
                    {
                            Color X0 = GetPixelColor (pixelarraymap, xx + 1, yy);
                            Color X1 = GetPixelColor (pixelarraymap, xx - 1, yy);

                            Color Y0 = GetPixelColor (pixelarraymap, xx, yy + 1);
                            Color Y1 = GetPixelColor (pixelarraymap, xx, yy - 1);

                            float Xd = (X0.getRed() - X1.getRed())
                                     + (X0.getGreen() - X1.getGreen())
                                     + (X0.getBlue() - X1.getBlue());

                            float Yd = (Y0.getRed() - Y1.getRed())
                                     + (Y0.getGreen() - Y1.getGreen())
                                     + (Y0.getBlue() - Y1.getBlue());

                            // maximum for Xd, Yd is: (MAX - 0) + (MAX - 0) + (MAX - 0) = 3 * MAX

                            Xd /= (float)(3 * 255);
                            Yd /= (float)(3 * 255);

                            float Nx = Xd;
                            float Ny = Yd;
                            float Nz = (float)(1 - Math.sqrt ((Xd * Xd) + (Yd * Yd)));

                            if (Nz < 0.0f)
                                    Nz = 0.0f;

                            nv[yy * imageWidth + xx][0] = Nx;
                            nv[yy * imageWidth + xx][1] = Ny;
                            nv[yy * imageWidth + xx][2] = Nz;
                    }
            }
    }
private Color GetPixelColor (int[] arr, int x, int y)
    {
            int pixel = arr [y * Width + x];

            int alpha = (pixel >> 24) & 0xff;
            int red   = (pixel >> 16) & 0xff;
            int green = (pixel >>  8) & 0xff;
            int blue  = (pixel      ) & 0xff;

            return (new Color (red, green, blue));
    }
    private float BumpIntensity (int lightX, int lightY, int pixelX, int pixelY)
    {
            float Nx, Ny, Nz;

            // get normal vector of map
            Nx = normalVectors[pixelY * Width + pixelX][0];
            Ny = normalVectors[pixelY * Width + pixelX][1];
            Nz = normalVectors[pixelY * Width + pixelX][2];

            // make vector from pixel to light
            float lightvX = (float)(lightX - pixelX);
            float lightvY = (float)(lightY - pixelY);
            float lightvZ = (float)(30.0f  - 0.0f);

            // normalize
            float length = (float)Math.sqrt (lightvX*lightvX + lightvY*lightvY + lightvZ*lightvZ);

            lightvX /= length;
            lightvY /= length;
            lightvZ /= length;

            // take dot product
            float intensity = (Nx * lightvX + Ny * lightvY + Nz * lightvZ);

            if (intensity < 0.0f)
                    intensity = 0.0f;

            return intensity;
    }
    private void ImageToRGBArray (Image image, int RGBarray[][])
    {
            // Store RGB values into array

            int imageWidth = image.getWidth (this);
            int imageHeight = image.getHeight (this);

            int[] pixelarray = new int [imageWidth * imageHeight];
            PixelGrabber pg = new PixelGrabber (image, 0, 0, imageWidth, imageHeight, pixelarray, 0, imageWidth);

            try {
                    pg.grabPixels ();
            }
            catch (InterruptedException e) {
                    System.err.println("interrupted waiting for pixels!");
            }

            for (int xx = 0; xx < Width; xx++)
            {
                    for (int yy = 0; yy < Height; yy++)
                    {
                            Color c = GetPixelColor (pixelarray, xx, yy);

                            RGBarray[yy * imageWidth + xx][0] = (int)c.getRed ();
                            RGBarray[yy * imageWidth + xx][1] = (int)c.getGreen ();
                            RGBarray[yy * imageWidth + xx][2] = (int)c.getBlue ();
                    }
            }
    }
    public void setOpacity(float opacity, int rop) {
        scales[3] = opacity;
        switch (rop){
            case 1:
                rop1 = new RescaleOp(scales, offsets, null);
            case 2:
                rop2 = new RescaleOp(scales, offsets, null);
            case 3:
                rop3 = new RescaleOp(scales, offsets, null);
            case 4:
                rop4 = new RescaleOp(scales, offsets, null);
        }       
    }
    public void setStatus(int status){
        this.status = status;
        if(status != 1)
            xname = 0;
    }    
    public void setXName(String songname){
        waiting = false;
        this.songname = songname;
        xnamemax = songname.length()*7*(-1);
        xname = 0;
    }
    public void setControlSelected(int control){
        this.controlselect = control;
    }
    public void setGainBarNum(int barnum, int level){
        this.gainbarnum = barnum+1;
        this.volumelevel = level;        
    }
    public void setPanPosition(int position, int value){
        this.panposition = position;
        this.panvalue = value;
    }
    public void setMode(int mode){
        this.mode =  mode;
    }
    public int getMode(){
        return mode;
    }
    public void showText(boolean accept){
        this.showtext = accept;
    }
    public String getTextStatus(){
        if(this.showtext == true)
            return "show";
        else
            return "hide";
    }
    public void setBar(boolean barnum){
        this.barnum = barnum;
    }
    public boolean getBar(){
        return barnum;
    }
    private void drawSoul(){
        if(soulready == false){
            if(xsword1 > 150){
                xsword1 -=4;
                ysword1 = 86-(int)((((177-xsword1))*28)/9);
                xsword5 +=4;
                ysword5 = (int)(xsword5*(float)(47/14));
                if((1.0f - (float)(168-xsword1)/20f)<0)
                    setOpacity(0.0f, 1);
                else
                setOpacity((1.0f - (float)(168-xsword1)/20f), 1);
            }
            if(xsword2 > 150){
                xsword2 -=2;
                ysword2 = 86-(int)((((177-xsword2))*28)/9);
                xsword6 +=2;
                ysword6 = (int)(xsword6*(float)(47/14));
                if((0.9f - (float)(168-xsword2)/20f)<0)
                    setOpacity(0.0f, 2);
                else
                setOpacity(0.9f - (float)(168-xsword2)/20f, 2);
           }
            if(xsword3 > 150){
                xsword3 --;
                ysword3 = 86-(int)((((177-xsword3))*28)/9);
                xsword7 ++;
                ysword7 = (int)(xsword7*(float)(47/14));
                if((0.8f - (float)(168-xsword3)/20f)<0)
                    setOpacity(0.0f, 3);
                else
                setOpacity(0.8f - (float)(168-xsword3)/20f, 3);
            }
            if(xsword4 > 150){
//                    }
                sword4delay ++;
                if(sword4delay == 2){
                    sword4delay = 0;
                    xsword4 --;
                    ysword4 = 86-(int)((((177-xsword4))*28)/9);
                    xsword8 ++;
                    ysword8 = (int)(xsword8*(float)(47/14));
                }
                if((0.7f - (float)(168-xsword4)/20f)<0)
                    setOpacity(0.0f, 4);
                else
                    setOpacity(0.7f - (float)(168-xsword4)/20f, 4);

            }
            if(xsword4 <= 150){
                resetAllSwordPosition();
            }
        }  
    }
    private void resetAllSwordPosition(){
        xsword1 = xsword2 = xsword3 = xsword4 = 168;
        ysword1 = ysword2= ysword3 = ysword4 = 62;
        xsword5 = xsword6 = xsword7 = xsword8 = 16;
        ysword5 = ysword6 = ysword7 = ysword8 = 47;
        soulready = true;
    }
    private void drawText(float[] sample, float f){
        float[] wFFT = fft.calculate(sample);
        float wSadfrr = (saDecay * f);
        //float wBw = ((float) width / (float) saBands);
        for (int a = 0, bd = 0; bd < saBands; a += saMultiplier, bd++) {
            float wFs = 0;
            // -- Average out nearest bands.
            for (int b = 0; b < saMultiplier; b++) {
                wFs += wFFT[a + b];
            }
            // -- Log filter.
            wFs = (wFs * (float) Math.log(bd + 2));
            if (wFs > 1.0f) {
                wFs = 1.0f;
            }
            // -- Compute SA decay...
            if (wFs >= (old_FFT[a] - wSadfrr)) {
                old_FFT[a] = wFs;
            } else {
                old_FFT[a] -= wSadfrr;
                if (old_FFT[a] < 0) {
                    old_FFT[a] = 0;
                }
                wFs = old_FFT[a];
            }           
            setGraphicsText((int)(wFs*80), bd);
            setGraphicsImage((int)(wFs*60));
        }
        repaint();
    }
    private void setGraphicsText(int h, int band){
        switch (band){
            case 1:{
                sh1 = 105 - h;
                break;                
            }
            case 3:{
                xsd2 = 138 + h;
                sh2 = 105 - h;
                break;
            }
            case 5:{
                xsd3 = 138 + h;
                break;
            }
            case 7:{
                xsd4 = 138 + h;
                sh4 = 105 + h;
                break;
            }
            case 9:{
                sh5 = 105 + h;
                break;
            }
            case 11:{
                xsd6 = 138 -h;
                sh6 = 105 + h;
                break;
            }
            case 13:{
                xsd7 = 138 - h;
                break;
            }
            case 15:{
                xsd8 = 138 - h;
                sh8 = 105 - h;                
                break;
            }
        }
        xs2 = 135 - h;
        yt2 = 105 + (h/4);
        sizes2 = h + 12;
    }
    private void setGraphicsImage(int size){
        imagex = 215;
        imagew = 35;
        imagex -= size;
        if(imagex < 185)
            imagex = 185;
        imagew += (215 - imagex)*2;
        size *=2;
        //Gan cho light
        if(size > 40){
            lightdelay = 0;
            light = (float) 0.5;
            lightx = rd.nextInt(300);
            lighty = rd.nextInt(200);
            disturb(lightx, lighty);
        }
    }
    private void drawSpectrum(float[] pSample, float pFrrh){       
        float c = 35;
        float[] wFFT = fft.calculate(pSample);
        float wSadfrr = (saDecay * pFrrh);
        //float wBw = ((float) width / (float) saBands);
        float wBw = 11;
        for (int a = 0, bd = 0; bd < saBands; a += saMultiplier, bd++) {
            float wFs = 0;
            // -- Average out nearest bands.
            for (int b = 0; b < saMultiplier; b++) {
                wFs += wFFT[a + b];
            }
            // -- Log filter.
            wFs = (wFs * (float) Math.log(bd + 2));
            if (wFs > 1.0f) {
                wFs = 1.0f;
            }
            // -- Compute SA decay...
            if (wFs >= (old_FFT[a] - wSadfrr)) {
                old_FFT[a] = wFs;
            } else {
                old_FFT[a] -= wSadfrr;
                if (old_FFT[a] < 0) {
                    old_FFT[a] = 0;
                }
                wFs = old_FFT[a];
            }            
            setGraphicsSpectrum((int) c, 170 - (int) (wFs * height * 16), (int) wBw - 1, (int) (wFs * height * 16), bd);
            c += wBw;
        }        
        repaint();
    }
    protected void setGraphicsSpectrum(int x, int y, int width, int height,int band){
        if(y - 2 <= peaks[band]){
            peaks[band] = y - 2;
            if(y <= 0)
                peaks[band] = 0;
            peaksDelay[band] = 0;
        }
        else{
            peaksDelay[band]++;
            if (peaksDelay[band] > 10) {
                peaks[band]+=5;
            }
            if (peaks[band]>= y - 2) {
                peaks[band] = y - 2;
            }
            if(peaks[band] >= 168)
                peaks[band] = 168;
        }
        if(band == 1){
            if(height > 80){
                soulready = false;
            }
        }
        this.x[band] = x;        
        this.y[band] = y;
        this.barheight[band]= height;
        this.barwidth[band] = width;
        this.yp[band] = peaks[band];
        if(band%2 == 0){
            if(xshape[band/2] < height/3){
                shapered[band/2] = rd.nextInt(255);
                shapegreen[band/2] = rd.nextInt(255);
                shapeblue[band/2] = rd.nextInt(255);
                shape[band/2] = rd.nextInt(4);
                if(shape[band/2] == 2){
                    arcstartangle[band/2] = rd.nextInt(360);
                    arcangle[band/2] = rd.nextInt(360 - arcstartangle[band/2]);
                }
                if(shape[band/2] == 3){
                    arcwidth[band/2] = xshape[band/2]*2;
                    archeight[band/2] = xshape[band/2]*2;
                }
                shapeheartx[band/2] = rd.nextInt(300);
                shapehearty[band/2] = rd.nextInt(200);
                xshape[band/2] = height/3;
            }
            else{
                xshape[band/2] --;
                if((shapered[band/2]>shapegreen[band/2])&&(shapered[band/2]>shapeblue[band/2])){
                    shapered[band/2] -= 10;
                    if(shapered[band/2] < 0)
                        shapered[band/2] = 0;
                }
                else if((shapegreen[band / 2] > shapered[band / 2]) && (shapegreen[band / 2] > shapeblue[band / 2])){
                    shapegreen[band/2] -= 10;
                    if(shapegreen[band/2] < 0)
                        shapegreen[band/2] = 0;
                }
                else if((shapeblue[band / 2] > shapered[band / 2]) && (shapeblue[band / 2] > shapered[band / 2])){
                    shapeblue[band/2] -= 10;
                    if(shapeblue[band/2] < 0)
                        shapeblue[band/2] = 0;
                }
                else{
                    if(shapered[band/2] < 0)
                        shapered[band/2] = 0;
                    shapegreen[band/2] -= 10;
                    if(shapegreen[band/2] < 0)
                        shapegreen[band/2] = 0;
                    shapeblue[band/2] -= 10;
                    if(shapeblue[band/2] < 0)
                        shapeblue[band/2] = 0;
                }
            }
//            System.out.println(xshape[1]);
        }
    }
    private void drawCircle(float[] left, float[] right, float f, boolean circle){
        float[] wFFTl = fft.calculate(left);
        float wSadfrr = (saDecay * f);
        //float wBw = ((float) width / (float) saBands);
        for (int a = 0, bd = 0; bd < saBands; a += saMultiplier, bd++) {
            float wFs = 0;
            // -- Average out nearest bands.
            for (int b = 0; b < saMultiplier; b++) {
                wFs += wFFTl[a + b];
            }
            // -- Log filter.
            wFs = (wFs * (float) Math.log(bd + 2));
            if (wFs > 1.0f) {
                wFs = 1.0f;
            }
            // -- Compute SA decay...
            if (wFs >= (old_FFT[a] - wSadfrr)) {
                old_FFT[a] = wFs;
            } else {
                old_FFT[a] -= wSadfrr;
                if (old_FFT[a] < 0) {
                    old_FFT[a] = 0;
                }
                wFs = old_FFT[a];
            }            
            setGraphicsLeft((int)(wFs*80), circle);
        }
        float[] wFFTr = fft.calculate(right);
        //float wBw = ((float) width / (float) saBands);
        for (int a = 0, bd = 0; bd < saBands; a += saMultiplier, bd++) {
            float wFs = 0;
            // -- Average out nearest bands.
            for (int b = 0; b < saMultiplier; b++) {
                wFs += wFFTr[a + b];
            }
            // -- Log filter.
            wFs = (wFs * (float) Math.log(bd + 2));
            if (wFs > 1.0f) {
                wFs = 1.0f;
            }
            // -- Compute SA decay...
            if (wFs >= (old_FFT[a] - wSadfrr)) {
                old_FFT[a] = wFs;
            } else {
                old_FFT[a] -= wSadfrr;
                if (old_FFT[a] < 0) {
                    old_FFT[a] = 0;
                }
                wFs = old_FFT[a];
            }
            //setGraphicsVar((int) c, 130 - (int) (wFs * height * 10), (int) wBw - 1, (int) (wFs * height * 10), bd+1);
            //(int)wFs * height * 10;
            setGraphicsRight((int)(wFs*80), circle);
        }
        repaint();
    }
    private void drawCircle2(float[] pSample, float pFrrh){
        float[] wFFT = fft.calculate(pSample);
        float wSadfrr = (saDecay * pFrrh);
        //float wBw = ((float) width / (float) saBands);
        for (int a = 0, bd = 0; bd < saBands; a += saMultiplier, bd++) {
            float wFs = 0;
            // -- Average out nearest bands.
            for (int b = 0; b < saMultiplier; b++) {
                wFs += wFFT[a + b];
            }
            // -- Log filter.
            wFs = (wFs * (float) Math.log(bd + 2));
            if (wFs > 1.0f) {
                wFs = 1.0f;
            }
            // -- Compute SA decay...
            if (wFs >= (old_FFT[a] - wSadfrr)) {
                old_FFT[a] = wFs;
            } else {
                old_FFT[a] -= wSadfrr;
                if (old_FFT[a] < 0) {
                    old_FFT[a] = 0;
                }
                wFs = old_FFT[a];
            }   
            setGraphicsCircle((int)(wFs*80), bd);
        }
        
    }
    private void drawScope(float[] pSample, float pFrrh){
        float[] wFFT = fft.calculate(pSample);
        float wSadfrr = (saDecay * pFrrh);
        //float wBw = ((float) width / (float) saBands);
        for (int a = 0, bd = 0; bd < saBands; a += saMultiplier, bd++) {
            float wFs = 0;
            // -- Average out nearest bands.
            for (int b = 0; b < saMultiplier; b++) {
                wFs += wFFT[a + b];
            }
            // -- Log filter.
            wFs = (wFs * (float) Math.log(bd + 2));
            if (wFs > 1.0f) {
                wFs = 1.0f;
            }
            // -- Compute SA decay...
            if (wFs >= (old_FFT[a] - wSadfrr)) {
                old_FFT[a] = wFs;
            } else {
                old_FFT[a] -= wSadfrr;
                if (old_FFT[a] < 0) {
                    old_FFT[a] = 0;
                }
                wFs = old_FFT[a];
            }            
            setGraphicsScope((int)(wFs*100));
            
        }
        repaint();
    }
    private void setGraphicsRealScope(float[] pSample){
        int a = 0;
        for(a = 0, bar = 0; bar < 200; a+=9, bar++)
            scope[bar] = (int)(pSample[a] * 50)+100;
        repaint();
    }
    private void setGraphicsScope(int newheight){
        newheight = 100 - newheight;
        /*if(newheight < 8)
            newheight = 8;
         *
         */
        if(scopedelay < 0){
            scopedelay = 5;
            for(bar = 199; bar > 0; bar --)
                scope[bar] = scope[bar-1];
            scope[0] = newheight;
        }
        scopedelay --;
    }
    private void setGraphicsLeft(int radd, boolean circle){
        if(circle == true){
            xc1 = 115;
            yc1 = 65;
            wc1 = hc1 = 70;
            xc1 -= radd;
            if(xc1 < 50)
                xc1 = 50;
            yc1 -= radd;
            if(yc1 < 0)
                yc1 = 0;
            wc1 += radd*2;
            if(wc1 > 200)
                wc1 = 200;            
            hc1 = wc1;
            wave = false;            
            if(xc1 == 50){
                if(oxc11 != xc1)
                    oxc11 = xc1;
                else if(oxc12 != xc1){
                    oxc12 = xc1;
                    wave = true;
                }
            }
            if(oxc12 == 50){
                oxc11 = 0;
                oxc12 = 0;
            }
            if(wave == true){
                if(bc1c1ready == true)
                    bc1c1ready = false;
                else if(bc2c1ready == true)
                    bc2c1ready = false;
                else if(bc3c1ready == true)
                    bc3c1ready = false;

            }
            if(bc1c1ready == false){
                    if(bc1c1delay == 0){
                        bc1c1delay = 1;
                        xbc1c1 --;
                        ybc1c1 --;
                        wbc1c1 +=2;                        
                        if(xbc1c1 < -40){
                            xbc1c1 = xc1;
                            ybc1c1 = yc1;
                            wbc1c1 = wc1;
                            bc1c1ready = true;
                        }
                    }
                    else
                        bc1c1delay --;
            }
            else{
                xbc1c1 = xc1;
                ybc1c1 = yc1;
                wbc1c1 = wc1;
            }
            if(bc2c1ready == false){
                    if(bc2c1delay == 0){
                        bc2c1delay = 1;
                        xbc2c1 --;
                        ybc2c1 --;
                        wbc2c1 +=2;
                        if(xbc2c1 < -40){
                            xbc2c1 = xc1;
                            ybc2c1 = yc1;
                            wbc2c1 = wc1;
                            bc2c1ready = true;
                        }
                    }
                    else
                        bc2c1delay --;
            }
            else{                
                xbc2c1 = xc1;
                ybc2c1 = yc1;
                wbc2c1 = wc1;
            }
            if(bc3c1ready == false){
                    if(bc3c1delay == 0){
                        bc3c1delay = 1;
                        xbc3c1 --;
                        ybc3c1 --;
                        wbc3c1 +=2;
                        if(xbc3c1 < -40){
                            xbc3c1 = xc1;
                            ybc3c1 = yc1;
                            wbc3c1 = wc1;
                            bc3c1ready = true;
                        }
                    }
                    else
                        bc3c1delay --;
            }
            else{
                xbc3c1 = xc1;
                ybc3c1 = yc1;
                wbc3c1 = wc1;
            }   
            if(150 - xc1 > 50)
                d1 = 175 - xc1;
            else
                d1 = 65;
            angle1 = angle1 + 0.001;
            x1 = (int)(150 + d1 * Math.cos(angle1));
            y1 = (int)(100 + d1 * Math.sin(angle1));
            angle2 = angle2 + 0.001;
            x2 = (int)(150 + d1 * Math.cos(angle2));
            y2 = (int)(100 + d1 * Math.sin(angle2));
            angle3 = angle3 + 0.001;
            x3 = (int)(150 + d1 * Math.cos(angle3));
            y3 = (int)(100 + d1 * Math.sin(angle3));
            angle4 = angle4 + 0.001;
            x4 = (int)(150 + d1 * Math.cos(angle4));
            y4 = (int)(100 + d1 * Math.sin(angle4));
            angle5 = angle5 + 0.001;
            x5 = (int)(150 + d1 * Math.cos(angle5));
            y5 = (int)(100 + d1 * Math.sin(angle5));
            angle6 = angle6 + 0.001;
            x6 = (int)(150 + d1 * Math.cos(angle6));
            y6 = (int)(100 + d1 * Math.sin(angle6));
            angle7 = angle7 + 0.001;
            x7 = (int)(150 + d1 * Math.cos(angle7));
            y7 = (int)(100 + d1 * Math.sin(angle7));
            angle8 = angle8 + 0.001;
            x8 = (int)(150 + d1 * Math.cos(angle8));
            y8 = (int)(100 + d1 * Math.sin(angle8));
        }
        else if(circle == false){
            xc1 = 115;
            yc1 = 65;
            wc1 = hc1 = 70;
            xc1 -= radd;
            if(xc1 < 50)
                xc1 = 50;
            yc1 -= radd;
            if(yc1 < 0)
                yc1 = 0;
            wc1 += radd*2;            
            if(wc1 > 200)
                wc1 = 200;            
            hc1 = wc1;            
            xmc1c2 = mc1heart - 15;
            ymc1c2 = 85;
            wmc1c2 = hmc1c2 = 30;
            xmc1c2 -= radd/2;
            ymc1c2 -= radd/2;
            wmc1c2 += radd;
            hmc1c2 += radd;
            xmc2c2 = xmc1c2 + 5;
            ymc2c2 = ymc1c2 + 5;
            wmc2c2 = hmc2c2 = wmc1c2 - 10;
            xmc3c2 = xmc1c2 + 8;
            ymc3c2 = ymc1c2 + 8;
            wmc3c2 = hmc3c2 = wmc1c2 - 16;
        }
    }
    private void setGraphicsRight(int radd, boolean circle){
        if(circle == true){
            xc5 = 140;
            yc5 = 90;
            wc5 = hc5 = 20;
            xc5 -= radd;
            if(xc5 < 40)
                xc5 = 40;
            yc5 -= radd;
            if(yc5 < 5)
                yc5 = 5;
            hc5 = wc5 += radd*2;
            if(wc5 > 220)
                wc5 = 220;
            if(hc5 > 190)
                hc5 = 190;
            clipoval = new Ellipse2D.Double(xc5, yc5, wc5, hc5);
        }
        else if(circle == false){
            xmc4c2 = mc2heart - 16;
            ymc4c2 = 85;
            wmc4c2 = hmc4c2 = 30;
            xmc4c2 -= radd/2;
            ymc4c2 -= radd/2;
            wmc4c2 += radd;
            hmc4c2 += radd;
            xmc5c2 = xmc4c2 + 5;
            ymc5c2 = ymc4c2 + 5;
            wmc5c2 = hmc5c2 = wmc4c2 - 10;
            xmc6c2 = xmc4c2 + 8;
            ymc6c2 = ymc4c2 + 8;
            wmc6c2 = hmc6c2 = wmc4c2 - 16;
        }
    }
    protected void setGraphicsCircle(int circlewidth, int circle){
        //Toa do tam O cua tat ca cac hinh tron la 150,100
        //Toa do hinh tron xanh ban dau la 75, 40 voi width va height = 70
        //Tao do hinh tron den ban dau la 92, 57 voi width va height = 35
        //xc1 = 75;
        //yc1 = 40;
        xc1 = 115;
        yc1 = 65;
        xc2 = 124;
        yc2 = 74;
        wc1 = hc1 = 70;       
        wc2 = hc2 = 52;
        xc3 = 131;
        yc3 = 81;
        wc3 = hc3 = 38;
        xc4 = 136;
        yc4 = 86;
        wc4 = hc4 = 28;
        xc5 = 140;
        yc5 = 90;
        wc5 = hc5 = 20;
        xc1 -= circlewidth;
        if(xc1 < 50)
            xc1 = 50;
        yc1 -= circlewidth;
        if(yc1 < 0)
            yc1 = 0;
        wc1 += circlewidth*2;
        if(wc1 > 200)
            wc1 = 200;        
        hc1 = wc1;        
        xc2 -= circlewidth;
        if(xc2 < xc1+9)
            xc2 = xc1 + 9;
        yc2 -= circlewidth;
        if(yc2 < yc1+9)
            yc2 = yc1 + 9;
        wc2 += circlewidth*2;
        if(wc2 > 182)
            wc2 = 182;
        hc2 = wc2;        
        xc3 -= circlewidth;
        if(xc3 < xc2+7)
            xc3 = xc2 + 7;
        yc3 -= circlewidth;
        if(yc3 < yc2+7)
            yc3 = yc2 + 7;
        wc3 += circlewidth*2;
        if(wc3 > 168)
            wc3 = 168;
        hc3 = wc3;        
        xc4 -= circlewidth;
        if(xc4 < xc3+5)
            xc4 = xc3 + 5;
        yc4 -= circlewidth;
        if(yc4 < yc3+5)
            yc4 = yc3 + 5;
        wc4 += circlewidth*2;
        if(wc4 > 158)
            wc4 = 158;        
        hc4 = wc4;        
        xc5 -= circlewidth;
        if(xc5 < xc4+4)
            xc5 = xc4 + 4;
        yc5 -= circlewidth;
        if(yc5 < yc4+4)
            yc5 = yc4 + 4;
        wc5 += circlewidth*2;
        if(wc5 > 150)
            wc5 = 150;
        hc5 = wc5;        
    }    
    private float[] stereoMerge(float[] pLeft, float[] pRight) {
        for (int a = 0; a < pLeft.length; a++) {
            pLeft[a] = (pLeft[a] + pRight[a]) / 2.0f;
        }
        return pLeft;
    }
    public void setBlinkPosition(int position){
        this.blinkposition = position - 3;
    }
    private void initialize() {
        setSpectrumAnalyserBandCount(DEFAULT_SPECTRUM_ANALYSER_BAND_COUNT);
        setSpectrumAnalyserFFTSampleSize(DEFAULT_SPECTRUM_ANALYSER_FFT_SAMPLE_SIZE);
        x = new int[20];
        y = new int[20];
        barheight = new int[20];
        barwidth = new int[20];
        yp = new int[20];
        for(bar = 0; bar < 20; bar++){
            x[bar] = y[bar] = barwidth[bar] = barheight[bar] = yp[bar]= -20;
        }
        scope = new int[220];
        for(bar = 0; bar < 200; bar++)
            scope[bar] = 100;
        //xc1 = 75;
        //yc1 = 40;
        xc1 = 115;
        yc1 = 65;
        xc2 = 124;
        yc2 = 74;
        wc1 = hc1 = 70;
        wc2 = hc2 = 52;
        //xc3 = 91;
        //yc3 = 56;
        xc3 = 131;
        yc3 = 81;
        wc3 = hc3 = 38;
        xc4 = 136;
        yc4 = 86;
        wc4 = hc4 = 28;
        xc5 = 140;
        yc5 = 90;
        wc5 = hc5 = 20;
        xsd1 = xsd2 = xsd3 = xsd4 = xsd5 = xsd6 = xsd7 = xsd8 = 138;
        sh1 = sh2 = sh3 = sh4 = sh5 = sh6 = sh7 = sh8 = 105;
        xs2 = 135;
        yt2 = 105;
        sizes2 = 12;
        xmc1c2 = 40;
        ymc1c2 = 85;
        wmc1c2 = hmc1c2 = 30;
        xmc2c2 = 45;
        ymc2c2 = 90;
        wmc2c2 = hmc2c2 = 20;
        xmc3c2 = 48;
        ymc3c2 = 93;
        wmc3c2 = hmc3c2 = 14;
        xmc4c2 = 230;
        ymc4c2 = 85;
        wmc4c2 = hmc4c2 = 30;
        xmc5c2 = 235;
        ymc5c2 = 90;
        wmc5c2 = hmc5c2 = 20;
        xmc6c2 = 238;
        ymc6c2 = 93;
        wmc6c2 = hmc6c2 = 14;
        xbc1c1 = xc1;
        ybc1c1 = yc1;
        wbc1c1 = wc1;
        xbc2c1 = xc1;
        ybc2c1 = yc1;
        wbc2c1 = wc1;
        xbc3c1 = xc1;
        ybc3c1 = yc1;
        wbc3c1 = wc1;
        x1 = (int)(150 + d1 * Math.cos(angle1));
        y1 = (int)(100 + d1 * Math.sin(angle1));
        x2 = (int)(150 + d1 * Math.cos(angle2));
        y2 = (int)(100 + d1 * Math.sin(angle2));
        x3 = (int)(150 + d1 * Math.cos(angle3));
        y3 = (int)(100 + d1 * Math.sin(angle3));
        x4 = (int)(150 + d1 * Math.cos(angle4));
        y4 = (int)(100 + d1 * Math.sin(angle4));
        x5 = (int)(150 + d1 * Math.cos(angle5));
        y5 = (int)(100 + d1 * Math.sin(angle5));
        x6 = (int)(150 + d1 * Math.cos(angle6));
        y6 = (int)(100 + d1 * Math.sin(angle6));
        x7 = (int)(150 + d1 * Math.cos(angle7));
        y7 = (int)(100 + d1 * Math.sin(angle7));
        x8 = (int)(150 + d1 * Math.cos(angle8));
        y8 = (int)(100 + d1 * Math.sin(angle8));
        
        
        avatar = this.getToolkit().getImage("lib/audio_info1.1.jar");    
        imagex = 215;
        imagew = 35;
        blinkposition = 0;
        controlselect = 0;
        gainbarnum = 10;
        volumelevel = 100;
        panposition = 25;
        panvalue = 0;
        xname = 0;
        status = 0;
        
        
        //Cac bien dung de ve soul
        background = this.getToolkit().getImage("lib/visual_colors.vsc");
        File file = new File("lib/visual_effect2.1.eft");
        try {
            swordsoul1 = ImageIO.read(file);
        } catch (IOException ex) {
            Logger.getLogger(SpectrumAnalyzer.class.getName()).log(Level.SEVERE, null, ex);
        }
        file = new File("lib/image_effect_1.0.lib");
        try {
            swordsoul2 = ImageIO.read(file);
        } catch (IOException ex) {
            Logger.getLogger(SpectrumAnalyzer.class.getName()).log(Level.SEVERE, null, ex);
        }        
        rop1 = new RescaleOp(scales, offsets, null);
        rop2 = new RescaleOp(scales, offsets, null);
        rop3 = new RescaleOp(scales, offsets, null);
        rop4 = new RescaleOp(scales, offsets, null);
        xsword1 = xsword2 = xsword3 = xsword4 = 168;
        ysword1 = ysword2= ysword3 = ysword4 = 62;
        xsword5 = xsword6 = xsword7 = xsword8 = 16;
        ysword5 = ysword6 = ysword7 = ysword8 = 47;
        bi = new BufferedImage(300, 300, BufferedImage.TYPE_INT_ARGB);
        soulg = bi.getGraphics();

        //Cac bien dung de ve colors
        rd = new Random();
        shape = new int[10];
        shapeheartx = new int[10];
        shapehearty = new int[10];
        xshape = new int[10];
        shapered = new int[10];
        shapegreen = new int[10];
        shapeblue = new int[10];
        arcstartangle = new int[10];
        arcangle = new int[10];
        arcwidth = new int[10];
        archeight = new int[10];
        for(int i = 0; i < 10; i++){
            shape[i] = 0;
            shapeheartx[i] = 0;
            shapehearty[i] = 0;
            xshape[i] = 0;
            shapered[i] = 0;
            shapegreen[i] = 0;
            shapeblue[i] = 0;
            arcstartangle[i] = 0;
            arcangle[i] = 0;
            arcwidth[i] = 0;
            archeight[i] = 0;

        }
        //Cac bien dung cho bump
        Image lightbackground = this.getToolkit().getImage("lib/light_effect.jar");
        Image map = this.getToolkit().getImage("lib/light_effect.jar");
        MediaTracker imageTracker = new MediaTracker (this);
        imageTracker.addImage (lightbackground, 0);
        imageTracker.addImage (map, 0);
        try {
                imageTracker.waitForAll ();
        }
        catch (InterruptedException e) {
                System.err.println("interrupted waiting for images!");
        }
        Width = lightbackground.getWidth (this);
        Height = lightbackground.getHeight (this);
        normalVectors = new float[Width * Height][3];
        FindNormalVectors (map, normalVectors);
        imgcolors = new int[Width * Height][3];
        ImageToRGBArray (lightbackground, imgcolors);
        buffer = new int[Width * Height];
        lightbackground.flush ();
	map.flush ();
        lightx = rd.nextInt(300);
        lighty = rd.nextInt(200);

        //Khoi tao cac  bien rain
        MediaTracker mt = new MediaTracker(this);
        im = getToolkit().getImage("lib/light_effect.jar");
        mt.addImage(im,0);
        try {
            mt.waitForID(0);
        } catch (InterruptedException e) {
            return;
        }
        iwidth = im.getWidth(this);
        iheight = im.getHeight(this);
        hwidth = iwidth>>1;
        hheight = iheight>>1;
        riprad=3;

        size = iwidth * (iheight+2) * 2;
        ripplemap = new short[size];
        ripple = new int[iwidth*iheight];
        texture = new int[iwidth*iheight];
        oldind = iwidth;
        newind = iwidth * (iheight+3);
        PixelGrabber pg = new PixelGrabber(im,0,0,iwidth,iheight,texture,0,iwidth);
          try {
                pg.grabPixels();
          } catch (InterruptedException e) {}
        source = new MemoryImageSource(iwidth, iheight, ripple, 0, iwidth);
        source.setAnimated(true);
        source.setFullBufferUpdates(true);
        image = createImage(source);
        offImage = new BufferedImage(iwidth, iheight, BufferedImage.TYPE_INT_ARGB);
        offGraphics = offImage.getGraphics();
      
     }
    public void disturb(int dx, int dy) {
      for (int j=dy-riprad;j<dy+riprad;j++) {
        for (int k=dx-riprad;k<dx+riprad;k++) {
          if (j>=0 && j<iheight && k>=0 && k<iwidth) {
	    ripplemap[oldind+(j*iwidth)+k] += 512;
          }
        }
      }
    }
    public void newframe() {
      //Toggle maps each frame
      ii=oldind;
      oldind=newind;
      newind=ii;

      ii=0;
      mapind=oldind;
      for (int yy=0;yy<iheight;yy++) {
        for (int xx=0;xx<iwidth;xx++) {
	  short data = (short)((ripplemap[mapind-iwidth]+ripplemap[mapind+iwidth]+ripplemap[mapind-1]+ripplemap[mapind+1])>>1);
          data -= ripplemap[newind+ii];
          data -= data >> 5;
          ripplemap[newind+ii]=data;

	  //where data=0 then still, where data>0 then wave
	  data = (short)(1024-data);

          //offsets
  	  aa =((xx-hwidth)*data/1024)+hwidth;
          bb =((yy-hheight)*data/1024)+hheight;

 	  //bounds check
          if (aa >= iwidth) aa = iwidth-1;
          if (aa < 0) aa = 0;
          if (bb >= iheight) bb = iheight-1;
          if (bb < 0) bb = 0;

          ripple[ii]=texture[aa+(bb*iwidth)];
          mapind++;
	  ii++;
        }
      }
    }
    public void setMousePosition(int x, int y){
        lightx = x;
        lighty = y;
        lightdelay =0;
        light = (float) 0.03;
        disturb(x, y);
    }
    public synchronized void setSpectrumAnalyserBandCount(int pCount) {
        saBands = pCount;
        peaks = new int[saBands];
        peaksDelay = new int[saBands];
        computeSAMultiplier();
    }
    public synchronized void setSpectrumAnalyserFFTSampleSize(int pSize) {
        saFFTSampleSize = pSize;
        fft = new KJFFT(saFFTSampleSize);
        old_FFT = new float[saFFTSampleSize];
        computeSAMultiplier();
    }
    private void computeSAMultiplier() {
        saMultiplier = (saFFTSampleSize / 2) / saBands;
    }
    public void startDSP(SourceDataLine line) {
        if (line != null) {
            m_line = line;
        }
        if (dsp == null) {
            dsp = new KJDigitalSignalProcessingAudioDataConsumer(2048, fps);
            dsp.add(this);
        }
        if ((dsp != null) && (m_line != null)) {
            if (dspStarted == true) {
                stopDSP();
            }
            dsp.start(m_line);
            dspStarted = true;
        }
    }
    public void stopDSP() {
        if (dsp != null) {
            dsp.stop();
            dspStarted = false;
        }        
    }
    public void closeDSP() {
        if (dsp != null) {
            stopDSP();
            dsp = null;
        }
    }
    public void setupDSP(SourceDataLine line) {
        if (dsp != null) {
            int channels = line.getFormat().getChannels();
            if (channels == 1) {
                dsp.setChannelMode(KJDigitalSignalProcessingAudioDataConsumer.CHANNEL_MODE_MONO);
            } else {
                dsp.setChannelMode(KJDigitalSignalProcessingAudioDataConsumer.CHANNEL_MODE_STEREO);
            }
            int bits = line.getFormat().getSampleSizeInBits();
            if (bits == 8) {
                dsp.setSampleType(KJDigitalSignalProcessingAudioDataConsumer.SAMPLE_TYPE_EIGHT_BIT);
            } else {
                dsp.setSampleType(KJDigitalSignalProcessingAudioDataConsumer.SAMPLE_TYPE_SIXTEEN_BIT);
            }
        }
    }
    public void writeDSP(byte[] pcmdata) {
        if ((dsp != null) && (dspStarted == true)) {
            dsp.writeAudioData(pcmdata);
        }
    }

}